﻿using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Web;
using WebChart;

namespace TSharp.Core.AppBox.Perfmon
{
    public class PerfmonUtil
    {
        #region   创建绘图上下文

        [ThreadStatic]
        private static WebChart.ChartEngine engine;
        /// <summary>
        /// 用来绘图的引擎，对每个线程会有不同的实例，线程内共享，web中session内共享。
        /// </summary>
        public static ChartEngine ChartEngineSession
        {
            get
            {
                if (HttpContext.Current == null || HttpContext.Current.Session == null)
                {
                    if (engine == null)
                    {
                        engine = CreateChartEngine();
                    }
                    return engine;
                }
                else
                {
                    var chartengine = HttpContext.Current.Session[HTTPCONTEXTKEY] as ChartEngine;
                    if (chartengine == null)
                        HttpContext.Current.Session[HTTPCONTEXTKEY] = chartengine = CreateChartEngine();
                    return chartengine;
                }
            }
        }
        private const string HTTPCONTEXTKEY = "___HTTPCONTEXTKEY_ChartEngine";
        #endregion

        #region 创建绘图引擎

        private static ChartEngine CreateChartEngine()
        {
            var _engine = new WebChart.ChartEngine();
            var line = _engine.Border;
            line.Color = Color.Blue;
            //<ChartTitle ForeColor="White" Text="WebChart Control" Font="Tahoma, 10pt, style=Bold"></ChartTitle>
            var t = _engine.Title = new ChartText();
            t.ForeColor = Color.White;
            t.Text = "性能监视";
            t.Font = new Font("Tahoma", 10, FontStyle.Bold);
            //<XTitle ForeColor="Black" Font="Tahoma, 8pt"></XTitle>
            _engine.YTitle = new ChartText();
            _engine.YTitle.Font = new Font("Tahoma", 8);
            _engine.YTitle.ForeColor = Color.Black;
            _engine.YTitle.Text = "Y标题";
            _engine.Padding = 10;
            _engine.HasChartLegend = true;
            _engine.TopChartPadding = 15;
            _engine.Size = new Size(1000, 600);
            _engine.LeftChartPadding = 10;
            _engine.GridLines = GridLines.Both;
            //  engine.ShowTitlesOnBackground = true;
            _engine.ShowXValues = true;
            //  engine.ShowYValues = true;
            _engine.XTicksInterval = 30;
            //  engine.YCustomStart = -1;
            // engine.YCustomEnd = 5;

            //<Background Type="LinearGradient" Angle="90" StartPoint="0, 0" ForeColor="#80FF80" EndPoint="100, 300" Color="CornflowerBlue" HatchStyle="ZigZag"></Background>
            var interior = _engine.Background;
            interior.Type = InteriorType.LinearGradient;
            interior.Angle = 90;
            interior.StartPoint = new Point(0, 0);
            interior.ForeColor = Color.FromArgb(0x80, 0xff, 0x80);
            interior.EndPoint = new Point(100, 300);
            interior.Color = Color.CornflowerBlue;
            interior.HatchStyle = HatchStyle.ZigZag;
            //<Border StartCap="Flat" EndCap="Flat" Width="0" DashStyle="Solid" Color="CornflowerBlue" LineJoin="Miter"></Border>
            line = _engine.Border;
            line.StartCap = LineCap.Flat;
            line.EndCap = LineCap.Flat;
            line.Width = 1;
            line.DashStyle = DashStyle.Solid;
            line.Color = Color.CornflowerBlue;
            line.LineJoin = LineJoin.Miter;
            //<PlotBackground Type="LinearGradient" Angle="90" StartPoint="0, 0" ForeColor="#FFFFC0" EndPoint="100, 300" Color="White" HatchStyle="Shingle"></PlotBackground>
            interior = _engine.PlotBackground;
            interior.Type = InteriorType.LinearGradient;
            interior.Angle = 90;
            interior.StartPoint = new Point(0, 0);
            interior.ForeColor = Color.FromArgb(0xff, 0xff, 0xc0);
            interior.EndPoint = new Point(100, 300);
            interior.Color = Color.White;
            interior.HatchStyle = HatchStyle.Shingle;
            //<YAxisFont ForeColor="Black" Font="Tahoma, 8pt"></YAxisFont>
            t = _engine.XAxisFont;
            t.ForeColor = Color.Black;
            t.Text = "性能监视";
            t.Font = new Font("Tahoma", 8, FontStyle.Bold);
            _engine.YAxisFont = t;
            //<XAxisFont ForeColor="Black" Font="Tahoma, 8pt"></XAxisFont>
            t = new ChartText();
            t.ForeColor = Color.Black;
            // t.Text = "性能监视";
            t.Font = new Font("Tahoma", 8, FontStyle.Bold);
            //<Legend Width="100" Font="Tahoma, 6pt">
            //    <Border StartCap="Flat" EndCap="Flat" Width="0" DashStyle="Solid" Color="Black" LineJoin="Miter"></Border>
            //    <Background Type="Solid" StartPoint="0, 0" ForeColor="Black" EndPoint="100, 100" Color="#FFFFC0" HatchStyle="Shingle"></Background>
            //</Legend>
            var legend = _engine.Legend;
            legend.Width = 200;
            legend.Font = new Font("Tahoma", 10, FontStyle.Bold);
            legend.Border.StartCap = LineCap.Flat;
            legend.Border.EndCap = LineCap.Flat;
            legend.Border.Width = 0;
            legend.Border.DashStyle = DashStyle.DashDot;
            legend.Border.Color = Color.Black;
            legend.Border.LineJoin = LineJoin.Miter;
            legend.Position = LegendPosition.Top;

            interior = legend.Background;
            interior.Type = InteriorType.Solid;
            interior.Angle = 90;
            interior.StartPoint = new Point(0, 0);
            interior.ForeColor = Color.Black;
            interior.EndPoint = new Point(100, 500);
            interior.Color = Color.FromArgb(0xff, 0xff, 0xc0);
            interior.HatchStyle = HatchStyle.Trellis;
            interior.CenterColor = Color.Blue;

            return _engine;
        }
        #endregion


        static System.Collections.Generic.Dictionary<string, Color> Colors = new System.Collections.Generic.Dictionary<string, Color>();
        static int allIndex = 0;
        static Color RandomColor(string key)
        {
            if (!Colors.ContainsKey(key))
            {
                var index = allIndex++ % all.Count;
                Debug.WriteLine(index);
                Colors.Add(key, all[index]);
            }
            return Colors[key];
        }
        static List<Color> all = new List<Color>(new Color[] { Color.Red, Color.Blue, Color.Green, Color.Black, Color.DarkOrange });
        public static int xLength = 30;

        #region 装载计数器

        [ThreadStatic]
        private static Dictionary<string, PCMonInstance> _pcMonInstances;
        /// <summary>
        /// 用来绘图的引擎，对每个线程会有不同的实例，线程内共享，web中session内共享。
        /// </summary>
        public static Dictionary<string, PCMonInstance> pcMonInstances
        {
            get
            {
                if (HttpContext.Current == null || HttpContext.Current.Session == null)
                {
                    if (_pcMonInstances == null)
                    {
                        _pcMonInstances = CreatePcMonInstances();
                    }
                    return _pcMonInstances;
                }
                else
                {
                    var pcMonInstances = HttpContext.Current.Session[HTTPCONTEXTPCMONINSTANCESKEY] as Dictionary<string, PCMonInstance>;
                    if (pcMonInstances == null)
                        HttpContext.Current.Session[HTTPCONTEXTPCMONINSTANCESKEY] = pcMonInstances = CreatePcMonInstances();
                    return pcMonInstances;
                }
            }
        }

        private static Dictionary<string, PCMonInstance> CreatePcMonInstances()
        {
            var ds = new Dictionary<string, PCMonInstance>();

            return ds;
        }
        private const string HTTPCONTEXTPCMONINSTANCESKEY = "___HTTPCONTEXTPCMONINSTANCESKEY";
        static public PCMonInstance LoadCounter(string counterDefinition)
        {
            try
            {
                PCMonInstance pcMonInstance = new PCMonInstance(counterDefinition);
                pcMonInstance.CreatePCInstance();
                return pcMonInstance;
            }
            catch (Exception innerEx)
            {
                Debug.WriteLine(innerEx.ToString());
                return null;
            }
        }

        #endregion



        public static void RefreshData(ChartEngine engine, QPerfMonFile config)
        {
            if (engine.Charts == null)
                engine.Charts = new ChartCollection(engine);
            var counterList = QPerfMonFile.Instance.CounterDefinitionList;
            for (int n = engine.Charts.Count - 1; n >= 0; n--)
            {
                var t = engine.Charts[n];
                if (!counterList.Contains(t.Name))
                {
                    ChartPointCollection d = t.Data;
                    d.Add(new ChartPoint(DateTime.Now.Ticks + "", 0));
                    if (d.Count > xLength)
                        d.RemoveAt(0);
                    float min, max, mean;
                    d.GetMinMaxMeanValue(out min, out max, out mean);
                    if (max == 0 && min == max)
                    {
                        engine.Charts.RemoveAt(n);
                        pcMonInstances.Remove(t.Name);
                    }
                }
            }
            float globalMin = 0, globalMax = 0;
            foreach (var counterDefinition in counterList)
            {
                #region 配置对象
                PCMonInstance p = null;
                if (!pcMonInstances.ContainsKey(counterDefinition))
                {
                    p = new PCMonInstance(counterDefinition);
                    try
                    {
                        p.CreatePCInstance();
                    }
                    catch (Exception ex)
                    {
                        p.LastError = ex.Message;
                    }

                    pcMonInstances.Add(counterDefinition, p);
                }
                else
                    p = pcMonInstances[counterDefinition];

                #endregion

                Chart c = engine.Charts.FindChart(counterDefinition);

                if (c == null)
                {
                    #region 创建绘图对象

                    Debug.WriteLine("配置文件计数器：" + p.Name);
                    var color = RandomColor(counterDefinition);
                    c = new WebChart.LineChart(GetDefaultData(), color);
                    c.Name = counterDefinition;

                    c.ShowLegend = true;

                    c.Legend = p.Name;
                    if (p.Scale > 1)
                        c.Legend += string.Format("(Scale/{0})", p.Scale);
                    if (!string.IsNullOrEmpty(p.LastError))
                        c.Legend += " [" + p.LastError + "]";
                    //图例的填充颜色
                    c.Fill.Color = color;
                    c.Fill.CenterColor = color;
                    c.Fill.ForeColor = color;

                    c.ShowLineMarkers = true;
                    //不能使用默认的，默认值会导致多个chart使用统一引用
                    var lm = c.LineMarker = LineMarker.Factory.CircleLineMarker;
                    lm.BorderColor = color;
                    lm.Color = color;
                    lm.Size = 5;

                    c.Line.Width = 1;
                    c.Line.StartCap = LineCap.Flat;
                    c.Line.EndCap = LineCap.Flat;
                    // AdjustableArrowCap myArrow = new AdjustableArrowCap(4, 4, false);
                    //CustomLineCap customArrow = myArrow;
                    c.Line.EndCap = LineCap.Flat;
                    // c.Line.CustomEndCap = myArrow;
                    c.Line.DashStyle = DashStyle.Solid;

                    c.DataLabels.Visible = true;
                    //c.DataLabels.NumberFormat = "C";
                    c.DataLabels.ForeColor = color;
                    c.ShowLegend = true;
                    engine.Charts.Add(c);
                    engine.ChartPadding = 10;
                    #endregion
                }

                ChartPointCollection d = c.Data;

                #region 取值

                //d.Add(new ChartPoint(DateTime.Now.Ticks + "", p.Value[p.Value.Count - 1]));
                try
                {
                    c.Legend = p.Name;
                    if (p.Scale > 1)
                        c.Legend += string.Format(" [Scale/{0}]", p.Scale);
                    if (!string.IsNullOrEmpty(p.LastError))
                        c.Legend += " [" + p.LastError + "]";

                    float v;
                    if (p.TryNextValue(out v))
                    {
                        d.Add(new ChartPoint(DateTime.Now.Ticks + "", v));
                    }
                    else
                    {
                        d.Add(new ChartPoint(DateTime.Now.Ticks + "", 0));
                    }
                }
                catch (Exception ee)
                {
                    Debug.WriteLine("计数器取值错误 >>> " + ee.Message);

                }
                #endregion

                if (d.Count > xLength)
                    d.RemoveAt(0);
                try
                {
                    float min, max, mean;
                    d.GetMinMaxMeanValue(out min, out max, out mean);
                    c.Legend += string.Format("  [Max:{0},Min:{1},Mean:{2}]", max, min, mean.ToString("0.00"));
                    globalMax = Math.Max(globalMax, max);
                    globalMin = Math.Min(globalMin, min);
                }
                catch (Exception)
                {

                }
            }

            try
            {
                var size = engine.Size;
                int Padding = 40;//高度总缩进，上下各缩进Padding/2
                var sacle = (globalMax - globalMin) * 1.0f / (size.Height + Padding);
                engine.YCustomStart = globalMin - Padding / 2 * sacle;
                engine.YCustomEnd = globalMax + Padding / 2 * sacle;
            }
            catch (Exception)
            {

            }
        }
        static private ChartPointCollection GetDefaultData()
        {
            ChartPointCollection d = new ChartPointCollection();
            for (int i = 0, n = xLength; i < n; i++)
            {
                d.Add(new ChartPoint(DateTime.Now.Ticks + "", 0));
            }
            return d;
        }


    }
}